/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 * Description: UDK log header file
 * Author: -
 * Create: 2021.4.19
 */
#ifndef UDK_LOG_H
#define UDK_LOG_H

#include <stdint.h>
#include <stdio.h>

#define MAX_LOG_LEN 1024
#define MAX_PATH_LEN 256

#define UDK_LOGTYPE_MALLOC      1 /* Log related to malloc. */
#define UDK_LOGTYPE_RING        2 /* Log related to ring. */
#define UDK_LOGTYPE_MEMPOOL     3 /* Log related to mempool. */
#define UDK_LOGTYPE_TIMER       4 /* Log related to timers. */
#define UDK_LOGTYPE_HASH        5 /* Log related to hash table. */
#define UDK_LOGTYPE_VDEV        6 /* Log related to virtual device */
#define UDK_LOGTYPE_ETHDEV      7 /* Log related to ether device */
#define UDK_LOGTYPE_MEMZONE     8 /* Log related to memzone. */
#define UDK_LOGTYPE_COMMON      9 /* Log related to common. */
#define UDK_LOGTYPE_MBUF        10 /* Log related to mbuf. */
#define UDK_LOGTYPE_USRNL       11 /* Log related to user netlink. */

#define UDK_LOGTYPE_USER1       15 /* User-defined log type 1. */
#define UDK_LOGTYPE_USER2       16 /* User-defined log type 2. */
#define UDK_LOGTYPE_USER3       17 /* User-defined log type 3. */
#define UDK_LOGTYPE_USER4       18 /* User-defined log type 4. */
#define UDK_LOGTYPE_USER5       19 /* User-defined log type 5. */
#define UDK_LOGTYPE_USER6       20 /* User-defined log type 6. */
#define UDK_LOGTYPE_USER7       21 /* User-defined log type 7. */
#define UDK_LOGTYPE_USER8       22 /* User-defined log type 8. */
#define UDK_LOGTYPE_USER9       23 /* User-defined log type 9. */
#define UDK_LOGTYPE_USER10      24 /* User-defined log type 10. */
#define UDK_LOGTYPE_USER11      25 /* User-defined log type 11. */
#define UDK_LOGTYPE_USER12      26 /* User-defined log type 12. */
#define UDK_LOGTYPE_FIRST_EXT_ID 27

/* Can't use 0, as it gives compiler warnings */
#define UDK_LOG_EMERG           0 /* System is unusable.               */
#define UDK_LOG_ALERT           1 /* Action must be taken immediately. */
#define UDK_LOG_CRIT            2 /* Critical conditions.              */
#define UDK_LOG_ERR             3 /* Error conditions.                 */
#define UDK_LOG_WARNING         4 /* Warning conditions.               */
#define UDK_LOG_NOTICE          5 /* Normal but significant condition. */
#define UDK_LOG_INFO            6 /* Informational.                    */
#define UDK_LOG_DEBUG           7 /* Debug-level messages.             */
#define UDK_LOG_MAX_LEVEL       8 /* Max-level.                        */

void udk_log_init(const char *log_tag);
void udk_log_set_global_level(uint32_t level);
void udk_log_set_log_prefix(void);
int udk_log_set_level(uint32_t logtype, uint32_t level);
int udk_vlog(const char *function, int line, uint32_t level, uint32_t id, const char *format, va_list ap);
int udk_log(const char *function, int line, uint32_t level, uint32_t logtype, const char *format, ...)
#ifdef __GNUC__
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2))
    __attribute__((cold))
#endif
#endif
    __attribute__((format(printf, 5, 6)));

struct log_ratelimit_state {
    uint64_t interval;
    int unit;
    int burst;
    int printed;
    int missed;
    uint64_t begin;
};

#define DEFINE_RATELIMIT_STATE(name, interval_init, burst_init) \
    static struct log_ratelimit_state name = {                  \
        .unit = 1,                                              \
        .interval = (interval_init),                            \
        .burst = (burst_init),                                  \
        .missed = 0,                                            \
        .printed = 0,                                           \
    }

int ratelimit(const char *func);
int udk_set_ratelimit_para(uint64_t interval, int burst);

#define UDK_LOG(l, t, ...) udk_log(__func__, __LINE__, UDK_LOG_##l, UDK_LOGTYPE_##t, #t ": " __VA_ARGS__)

#define UDK_LOG_LIMIT(l, t, ...)                                                            \
    do {                                                                                    \
        if (ratelimit(__func__)) {                                                          \
            udk_log(__func__, __LINE__, UDK_LOG_##l, UDK_LOGTYPE_##t, #t ": " __VA_ARGS__); \
        }                                                                                   \
    } while (0)

/* period log, the first time print times, then print one time every period time */
#define UDK_LOG_PERIOD(module, log_level, log_id, times, period, fmt, args...)       \
    do {                                                                             \
        static unsigned long pre_time = 0;                                           \
        static int32_t should_print = times;                                         \
        should_print = should_print < 0 ? 0 : should_print;                          \
        if ((should_print-- > 0) || (time_after_eq(jiffies, pre_time + (period)))) { \
            UDK_LOG(log_level, module, fmt "\n", ##args);                            \
            pre_time = jiffies;                                                      \
        }                                                                            \
    } while (0)

#endif
